Skip to content

Generate multiple types, one for each compatibility date that changes type signatures#137

Merged
penalosa merged 3 commits intomainfrom
penalosa/compat-dates
Nov 14, 2022
Merged

Generate multiple types, one for each compatibility date that changes type signatures#137
penalosa merged 3 commits intomainfrom
penalosa/compat-dates

Conversation

@penalosa
Copy link
Contributor

Blocked on #136

This generates a bazel-bin/types/definitions/*/api.d.ts and bazel-bin/types/definitions/*/api.ts file for the following compatibility dates:

The expandable diff shows how the (ambient) types have changed from the directly preceding older date

latest, the current up to date version of the runtime

diff bazel-bin/types/definitions/2022-08-04/api.d.ts bazel-bin/types/definitions/latest/api.d.ts
515a516,539
> declare abstract class ReadableStreamBYOBRequest {
>   readonly view: Uint8Array | null;
>   respond(param0: number): void;
>   respondWithNewView(param0: ArrayBuffer | ArrayBufferView): void;
>   readonly atLeast: number | null;
> }
> declare abstract class ReadableStreamDefaultController<R = any> {
>   readonly desiredSize: number | null;
>   close(): void;
>   enqueue(chunk?: R): void;
>   error(param0: any): void;
> }
> declare abstract class ReadableByteStreamController {
>   readonly byobRequest: ReadableStreamBYOBRequest | null;
>   readonly desiredSize: number | null;
>   close(): void;
>   enqueue(param0: ArrayBuffer | ArrayBufferView): void;
>   error(param0: any): void;
> }
> /** This Streams API interface represents a controller allowing control of a WritableStream's state. When constructing a WritableStream, the underlying sink is given a corresponding WritableStreamDefaultController instance to manipulate. */
> declare abstract class WritableStreamDefaultController {
>   readonly signal: AbortSignal;
>   error(param0?: any): void;
> }
593a618
>   get origin(): string;
596d620
<   get origin(): string;
613d636
<   get searchParams(): URLSearchParams;
616c639
<   toString(): string;
---
>   get searchParams(): URLSearchParams;
617a641
>   toString(): string;
621,625c645
<     init?:
<       | URLSearchParams
<       | string
<       | Record<string, string>
<       | [key: string, value: string][]
---
>     param0?: Iterable<Iterable<string>> | Record<string, string> | string
872a893,896
>   ReadableStreamBYOBRequest: typeof ReadableStreamBYOBRequest;
>   ReadableStreamDefaultController: typeof ReadableStreamDefaultController;
>   ReadableByteStreamController: typeof ReadableByteStreamController;
>   WritableStreamDefaultController: typeof WritableStreamDefaultController;
1573,1596d1596
< declare interface ReadableStreamBYOBRequest {
<   readonly view: Uint8Array | null;
<   respond(param0: number): void;
<   respondWithNewView(param0: ArrayBuffer | ArrayBufferView): void;
<   readonly atLeast: number | null;
< }
< declare interface ReadableStreamDefaultController<R = any> {
<   readonly desiredSize: number | null;
<   close(): void;
<   enqueue(chunk?: R): void;
<   error(param0: any): void;
< }
< declare interface ReadableByteStreamController {
<   readonly byobRequest: ReadableStreamBYOBRequest | null;
<   readonly desiredSize: number | null;
<   close(): void;
<   enqueue(param0: ArrayBuffer | ArrayBufferView): void;
<   error(param0: any): void;
< }
< /** This Streams API interface represents a controller allowing control of a WritableStream's state. When constructing a WritableStream, the underlying sink is given a corresponding WritableStreamDefaultController instance to manipulate. */
< declare interface WritableStreamDefaultController {
<   readonly signal: AbortSignal;
<   error(param0?: any): void;
< }
2022-08-04, #r2-bucket-list-respects-the-include-option

diff bazel-bin/types/definitions/2022-03-21/api.d.ts bazel-bin/types/definitions/2022-08-04/api.d.ts
2022-03-21, #global-navigator

diff bazel-bin/types/definitions/2022-01-31/api.d.ts bazel-bin/types/definitions/2022-03-21/api.d.ts
43a44,46
> declare abstract class Navigator {
>   readonly userAgent: string;
> }
883a887,888
>   navigator: Navigator;
>   Navigator: typeof Navigator;
1720a1726
> declare var navigator: Navigator;
2022-01-31, #settersgetters-on-api-object-prototypes

diff bazel-bin/types/definitions/2021-11-03/api.d.ts bazel-bin/types/definitions/2022-01-31/api.d.ts
48c48
<   readonly type: string;
---
>   get type(): string;
50c50
<   readonly eventPhase: number;
---
>   get eventPhase(): number;
52c52
<   readonly composed: boolean;
---
>   get composed(): boolean;
54c54
<   readonly bubbles: boolean;
---
>   get bubbles(): boolean;
56c56
<   readonly cancelable: boolean;
---
>   get cancelable(): boolean;
58c58
<   readonly defaultPrevented: boolean;
---
>   get defaultPrevented(): boolean;
60c60
<   readonly returnValue: boolean;
---
>   get returnValue(): boolean;
62c62
<   readonly currentTarget?: EventTarget;
---
>   get currentTarget(): EventTarget | undefined;
64c64
<   readonly srcElement?: EventTarget;
---
>   get srcElement(): EventTarget | undefined;
66c66
<   readonly timeStamp: number;
---
>   get timeStamp(): number;
68,69c68,70
<   readonly isTrusted: boolean;
<   cancelBubble: boolean;
---
>   get isTrusted(): boolean;
>   get cancelBubble(): boolean;
>   set cancelBubble(value: boolean);
121c122
<   readonly signal: AbortSignal;
---
>   get signal(): AbortSignal;
129,130c130,131
<   readonly aborted: boolean;
<   readonly reason: any;
---
>   get aborted(): boolean;
>   get reason(): any;
143,144c144,145
<   readonly size: number;
<   readonly type: string;
---
>   get size(): number;
>   get type(): string;
157,158c158,159
<   readonly name: string;
<   readonly lastModified: number;
---
>   get name(): string;
>   get lastModified(): number;
186c187
<   readonly subtle: SubtleCrypto;
---
>   get subtle(): SubtleCrypto;
300c301
<   readonly digest: Promise<ArrayBuffer>;
---
>   get digest(): Promise<ArrayBuffer>;
322,324c323,325
<   readonly encoding: string;
<   readonly fatal: boolean;
<   readonly ignoreBOM: boolean;
---
>   get encoding(): string;
>   get fatal(): boolean;
>   get ignoreBOM(): boolean;
333c334
<   readonly encoding: string;
---
>   get encoding(): string;
393,394c394,395
<   readonly body: ReadableStream | null;
<   readonly bodyUsed: boolean;
---
>   get body(): ReadableStream | null;
>   get bodyUsed(): boolean;
419,426c420,427
<   readonly status: number;
<   readonly statusText: string;
<   readonly headers: Headers;
<   readonly ok: boolean;
<   readonly redirected: boolean;
<   readonly url: string;
<   readonly webSocket: WebSocket | null;
<   readonly cf?: any;
---
>   get status(): number;
>   get statusText(): string;
>   get headers(): Headers;
>   get ok(): boolean;
>   get redirected(): boolean;
>   get url(): string;
>   get webSocket(): WebSocket | null;
>   get cf(): any | undefined;
433c434
<   readonly method: string;
---
>   get method(): string;
435c436
<   readonly url: string;
---
>   get url(): string;
437c438
<   readonly headers: Headers;
---
>   get headers(): Headers;
439,440c440,441
<   readonly redirect: string;
<   readonly fetcher: Fetcher | null;
---
>   get redirect(): string;
>   get fetcher(): Fetcher | null;
442,443c443,444
<   readonly signal: AbortSignal;
<   readonly cf?: any;
---
>   get signal(): AbortSignal;
>   get cf(): any | undefined;
494c495
<   readonly closed: Promise<void>;
---
>   get closed(): Promise<void>;
501c502
<   readonly closed: Promise<void>;
---
>   get closed(): Promise<void>;
515c516
<   readonly locked: boolean;
---
>   get locked(): boolean;
523,525c524,526
<   readonly closed: Promise<void>;
<   readonly ready: Promise<void>;
<   readonly desiredSize: number | null;
---
>   get closed(): Promise<void>;
>   get ready(): Promise<void>;
>   get desiredSize(): number | null;
537,538c538,539
<   readonly readable: ReadableStream<O>;
<   readonly writable: WritableStream<I>;
---
>   get readable(): ReadableStream<O>;
>   get writable(): WritableStream<I>;
590,601c591,612
<   href: string;
<   readonly origin: string;
<   protocol: string;
<   username: string;
<   password: string;
<   host: string;
<   hostname: string;
<   port: string;
<   pathname: string;
<   search: string;
<   readonly searchParams: URLSearchParams;
<   hash: string;
---
>   get href(): string;
>   set href(value: string);
>   get origin(): string;
>   get protocol(): string;
>   set protocol(value: string);
>   get username(): string;
>   set username(value: string);
>   get password(): string;
>   set password(value: string);
>   get host(): string;
>   set host(value: string);
>   get hostname(): string;
>   set hostname(value: string);
>   get port(): string;
>   set port(value: string);
>   get pathname(): string;
>   set pathname(value: string);
>   get search(): string;
>   set search(value: string);
>   get searchParams(): URLSearchParams;
>   get hash(): string;
>   set hash(value: string);
687c698
<   readonly readyState: number;
---
>   get readyState(): number;
689c700
<   readonly url: string | null;
---
>   get url(): string | null;
691c702
<   readonly protocol: string | null;
---
>   get protocol(): string | null;
693c704
<   readonly extensions: string | null;
---
>   get extensions(): string | null;
2021-11-03, #formdata-parsing-supports-file

diff bazel-bin/types/definitions/2021-01-01/api.d.ts bazel-bin/types/definitions/2021-11-03/api.d.ts
2021-01-01, before any compatibility date based changes

Two of these dates don't change the types, but I think they should, based on their description (cc @mrbbot):

  • 2022-08-04

    With the r2_list_honor_include flag set, the include argument to R2 list options is honored. With an older compatability date and without this flag, the include argument behaves implicitly as include: ["httpMetadata", "customMetadata"].

  • 2021-11-03

    Originally, the Workers runtime’s implementation of the FormData API incorrectly converted uploaded files to strings. Therefore, formData.get("filename") would return a string containing the file contents instead of a File object. This change fixes the problem, causing files to be represented using File as specified in the standard.

@penalosa penalosa force-pushed the penalosa/comments-exportable branch 4 times, most recently from 0c18f4e to be1df8e Compare October 28, 2022 13:10
@penalosa penalosa force-pushed the penalosa/compat-dates branch from 5359814 to 5cf109d Compare October 28, 2022 13:16
@penalosa penalosa force-pushed the penalosa/comments-exportable branch 2 times, most recently from 30ed347 to aad867d Compare November 2, 2022 13:49
@penalosa penalosa force-pushed the penalosa/compat-dates branch from 5cf109d to a8fba03 Compare November 2, 2022 14:04
@penalosa
Copy link
Contributor Author

penalosa commented Nov 2, 2022

@mrbbot This should be reviewable

Copy link
Contributor

@mrbbot mrbbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! 😃 Added some suggestions. 👍

@penalosa penalosa requested a review from mrbbot November 3, 2022 13:35
@mrbbot
Copy link
Contributor

mrbbot commented Nov 3, 2022

Looks good! ✅ Will approve once #136 is merged. 👍

@penalosa penalosa force-pushed the penalosa/comments-exportable branch 2 times, most recently from f98a4f6 to 29b7af0 Compare November 11, 2022 19:21
Base automatically changed from penalosa/comments-exportable to main November 14, 2022 10:39
@penalosa penalosa force-pushed the penalosa/compat-dates branch from 463ff5f to f20ad96 Compare November 14, 2022 11:50
# https://developers.cloudflare.com/workers/platform/compatibility-dates/#global-navigator
("2022-08-04", "2022-08-04"),
# Latest compatibility date
("2024-01-01", "experimental"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe push this date a lot further into the future? Also, do we want experimental to enable all flags even those without default on dates, or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed it to 2030. I don't think we want to enable things without a default on date, because that includes super experimental stuff like nodejs compat

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe experimental is the wrong name then, actually—I had latest before, but that didn't feel sufficiently warning-y

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stabilized could work? We only give default on dates once the flags have stabilised, but again not very warning-y. Let's stick with experimental. 👍

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this / how does this string get exposed to the customer? My (fuzzy) understanding is that this code will generate type information from enabling all compatibility flags which have enable-dates, and this type information is named "experimental"?

"latest" would make more sense to me, if so. When we assign an enable-date to a compatibility flag, we are saying that the new behavior is now the preferred, stable behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue that we saw with latest was that if someone is using that set of types in their typescript definitions, an update to the package would unexpectedly change their types (because new compatibility flags will be added and integrated into latest/experimental in the future), whereas pinning to a date version will guarantee type consistency as of that default on date. Currently, we think this'll be exposed as a reference to @cloudflare/workers-types/experimental or @cloudflare/workers-types/2022-11-03 in a user's typescript config.

Copy link
Contributor

@vlovich vlovich Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what Harris is saying is call it latest or now instead of experimental. experimental is misleading as to the name of the types. I concur with that.

A separate thing that's going to confuse me as an end user is that @cloudflare/workers-types/2022-11-03 is totally divorced from the compat date in wrangler.toml. In wrangler.toml I can pick any date. In the types I can only pick dates that mean something in the runtime. This is going to be a point of friction and confusion. You may want to make sure the docs are very clear here about guidance (e.g. "make sure that wrangler.toml picks the same date as the types for readability - the list of valid type dates are provided in the compat dates"). Alternatively, if you can provide types for all the dates such that they symlink to the real dates that have type signatures generated, then you can just say "specify the date same as you do in wrangler.toml" without forcing them to reference the (lagging & incomplete) docs to find a specific date that will work for them.

@penalosa penalosa merged commit ad56654 into main Nov 14, 2022
@penalosa penalosa deleted the penalosa/compat-dates branch November 14, 2022 12:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants